package com.gitee.wsl.compose.mvi

import androidx.compose.runtime.Composable
import androidx.compose.runtime.DisposableEffect
import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberCoroutineScope
import kotlinx.coroutines.CoroutineScope

abstract class ViewState {
    interface Factory

    /**
     * Called when the ViewModel is no longer used and will be destroyed.
     */
    open fun onCleared() {}
}

/**
 * A base ViewModel class that provides a CoroutineScope for coroutine management.
 * Subclasses can use the provided [scope] for launching coroutines.
 */
abstract class CoroutineViewState(
    private val scope: CoroutineScope
) : ViewState()

/**
 * The default implementation of ViewModel.Factory interface.
 * This factory can be used to create ViewModel instances.
 */
object DefaultViewModelFactory : ViewState.Factory

/**
 * Provides a ViewModel instance of type [VM] based on the specified [scope].
 * If [VM] is a subtype of [CoroutineViewState], it creates the ViewModel using the provided [scope].
 * Otherwise, it creates the ViewModel without any arguments.
 */
/*inline fun <reified VM : ViewState> ViewState.Factory.get(
    scope: CoroutineScope
): VM {
    return runCatching {
        VM::class.java.let { vmClass ->
            if (CoroutineViewState::class.java.isAssignableFrom(vmClass)) {
                vmClass.getConstructor(CoroutineScope::class.java).newInstance(scope)
            } else {
                vmClass.getConstructor().newInstance()
            }
        }
    }.getOrElse {
        throw IllegalStateException("Create Instance Failure (${VM::class.java})")
    } as VM
}*/

/**
 * Remembers a ViewModel instance of type [VM].
 * If [factory] is not provided, the [DefaultViewModelFactory] is used to get the ViewModel instance.
 * The ViewModel instance is associated with the provided [scope].
 * The ViewModel's [ViewState.onCleared] method is called when this Composable is disposed.
 */
/*
@Composable
inline fun <reified VM : ViewState> rememberViewState(
    factory: ViewState.Factory? = null,
    scope: CoroutineScope = rememberCoroutineScope()
): VM {
    val vm = remember { (factory ?: DefaultViewModelFactory).get<VM>(scope) }
    DisposableEffect(Unit) { onDispose { vm.onCleared() } }
    return vm
}*/
